package com.sicnu.websocket.websocket;

import com.sicnu.websocket.rd.MessageService;
import com.sicnu.websocket.vo.Message;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WebSocket 服务类
 * 负责接收前端发送数据，以及发送转发给对应用户
 */
@Slf4j
@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {


    private static Map<String, Session> ONLINE_USERS = new ConcurrentHashMap<>();

    private AtomicInteger saveCounter = new java.util.concurrent.atomic.AtomicInteger(0);
    private static final ConcurrentHashMap<String, CopyOnWriteArrayList<Message>> messageStore = new ConcurrentHashMap<>();
    private static MessageService messageService;

    @Autowired
    public void setMessageService(MessageService messageService) {
        WebSocketServer.messageService = messageService;
    }

    /**
     * 建立连接后处理方法
     *
     * @param session 一个特定的WebSocket连接
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        // 放入建立连接的用户
        ONLINE_USERS.put(userId, session);
        log.info("用户：{} 建立连接！当前在线人数：{}", userId, ONLINE_USERS.size());
    }


    /**
     * 连接关闭时处理方法
     *
     * @param session 一个特定的WebSocket连接
     */
    @OnClose
    public void onClose(Session session) {
        remove(session);
    }

    /**
     * 服务端收到客户端的消息后调用的方法
     *
     * @param session 一个特定的WebSocket连接
     * @param message 消息内容
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        log.info("收到消息，消息内容：【{}】", message);
        try {
            // 假设消息是JSON格式，包含 'to', 'from', 'content', 和 'username' 字段
            JSONObject jsonMessage = new JSONObject(message);
            String toUserId = jsonMessage.getString("to"); // 目标用户的ID
            String fromUserId = jsonMessage.getString("from"); // 发送者的ID
            String content = jsonMessage.getString("content");
            String username = jsonMessage.getString("username");

            if (StringUtils.isEmpty(toUserId)) {
                log.warn("无法确定消息的目标用户！");
                return;
            }

            // 构造 Message 对象并保存到 messageStore
            LocalDateTime timestamp = LocalDateTime.now();
            Message msg = new Message(Long.parseLong(fromUserId), Long.parseLong(toUserId), content, timestamp);
            saveMessage(msg);

            // 发送消息给指定用户
            sendMessage(content, toUserId, fromUserId, username, timestamp);

        } catch (Exception e) {
            log.error("解析消息失败：{}", e.getMessage(), e);
        }
    }

    /**
     * 给指定用户发送消息
     *
     * @param content 消息内容
     * @param toUserId  指定用户ID
     * @param fromUserId 发送者ID
     * @param username 发送者用户名
     */

    public void sendMessage(String content, String toUserId, String fromUserId, String username, LocalDateTime timestamp) {
        if (StringUtils.isEmpty(toUserId)) {
            return;
        }
        // --- 模拟失败逻辑 ---
        messageService.saveMessage(new Message());

        Session mySession = ONLINE_USERS.get(toUserId);
        if (mySession == null) {return;}
        ONLINE_USERS.forEach((userId, session) -> {
            // 排除自己
            if (!mySession.equals(session)) {
                // 给每个session都发一条消息
                if (session != null && session.isOpen()) {
                    try {
                        JSONObject jsonMessage = new JSONObject();
                        jsonMessage.put("from", fromUserId);
                        jsonMessage.put("username", username);
                        jsonMessage.put("content", content);
                        jsonMessage.put("time", timestamp.toString());

                        session.getAsyncRemote().sendText(jsonMessage.toString());
                        log.info("发送消息给用户 {}，消息内容：【{}】", toUserId, content);
                    } catch (Exception e) {
                        log.error("发送消息失败：{}", e.getMessage(), e);
                    }
                } else {
                    log.warn("目标用户 {} 不在线！", toUserId);
                }
            }
        });

    }


    /**
     * 出现错误时处理的方法
     *
     * @param session   一个特定的WebSocket连接
     * @param throwable 错误信息
     */
    @OnError
    public void onError(Session session, Throwable throwable) throws IOException {
        log.info("WebSocket异常：{}", throwable.getMessage(), throwable);
        if (session.isOpen()) {
            // 关闭连接
            session.close();
        }
        // 移除map中的session
        remove(session);
    }

    /**
     * 发送消息
     *
     * @param session 一个特定的WebSocket连接
     * @param message 消息内容
     */
    public void sendMessage(Session session, String message) {
        if (session != null && session.isOpen()) {
            session.getAsyncRemote().sendText(message);

            log.info("发送消息，消息内容：【{}】", message);
        }
    }

    /**
     * 群发消息，包括自己
     *
     * @param message 消息内容
     */
    public void sendMessageAll(String message) {
        ONLINE_USERS.forEach((userId, session) -> {
            // 给每个session都发一条消息
            this.sendMessage(session, message);
        });
    }

    /**
     * 群发消息，排除自己
     *
     * @param message   消息内容
     * @param mySession 当前自己的连接
     */
    public void sendMessageAll(String message, Session mySession) {
        ONLINE_USERS.forEach((userId, session) -> {
            // 排除自己
            if (!mySession.equals(session)) {
                // 给每个session都发一条消息
                this.sendMessage(session, message);
            }
        });
    }

    /**
     * 群发消息，排除自己
     *
     * @param message 消息内容
     * @param userId  当前用户ID
     */
    public void sendMessageAll(String message, String userId) {
        if (StringUtils.isEmpty(userId)) {
            return;
        }
        Session session = ONLINE_USERS.get(userId);
        sendMessageAll(message, session);
    }

    /**
     * 给指定用户发送消息
     *
     * @param message 消息内容
     * @param userId  指定用户ID
     */
    public void sendMessage(String message, String userId) {
        if (StringUtils.isEmpty(userId)) {
            return;
        }
        Session session = ONLINE_USERS.get(userId);
        this.sendMessage(session, message);
    }


    /**
     * 根据session移除在线用户
     *
     * @param session 一个特定的WebSocket连接
     */
    private void remove(Session session) {
        String userId = null;
        // 通过session 获取 userId，通过map中的value 获取key，此时map中的value和key都是唯一的
        for (Map.Entry<String, Session> entry : ONLINE_USERS.entrySet()) {
            if (entry.getValue().equals(session)) {
                userId = entry.getKey();
                break;
            }
        }
        if (null != userId) {
            // 移除用户
            ONLINE_USERS.remove(userId);
            log.info("用户：{} 关闭连接！当前在线人数：{}", userId, ONLINE_USERS.size());
        } else {
            log.error("关闭 WebSocket 连接失败！");
        }
    }

    public void saveMessage(Message message) {
        InMemoryMessageStore.addMessage(message);
    }

    public List<Message> getMessagesBetweenUsers(Long fromUserId, Long toUerId) {
        return InMemoryMessageStore.getMessages(fromUserId, toUerId);
    }
}
